/**
 * @FilePath     : log_broadcast_sink.h
 * @Description  : 日志广播 Sink - 将 spdlog 日志转发到 Qt 信号系统供 UI 使用
 */
#pragma once

#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/log_msg.h>
#include <QObject>
#include <QString>
#include <QDateTime>
#include <mutex>

namespace infrastructure::logging {

/**
 * @brief 日志广播信号发射器
 * @details 单例 QObject，用于将日志事件转换为 Qt 信号
 *          spdlog sink 在多线程环境下运行，通过 Qt::QueuedConnection 确保线程安全
 */
class LogBroadcastEmitter : public QObject {
    Q_OBJECT

public:
    /**
     * @brief 获取单例实例
     */
    static LogBroadcastEmitter* instance();

    /**
     * @brief 发射日志条目信号
     * @param timestamp 时间戳
     * @param level 日志级别
     * @param source 日志来源（logger名称）
     * @param message 日志消息
     */
    void emitLogEntry(const QDateTime& timestamp, const QString& level,
                      const QString& source, const QString& message);

signals:
    /**
     * @brief 日志接收信号
     * @details 当新日志到达时发射，UI层连接此信号以更新显示
     */
    void logReceived(const QDateTime& timestamp, const QString& level,
                     const QString& source, const QString& message);

private:
    explicit LogBroadcastEmitter(QObject* parent = nullptr);
    ~LogBroadcastEmitter() override = default;

    static LogBroadcastEmitter* s_instance;
    static std::mutex s_mutex;
};

/**
 * @brief spdlog 自定义 Sink，将日志广播到 UI
 * @tparam Mutex 互斥锁类型，通常使用 std::mutex
 */
template<typename Mutex>
class LogBroadcastSink : public spdlog::sinks::base_sink<Mutex> {
protected:
    /**
     * @brief 处理日志消息
     * @param msg spdlog 日志消息
     */
    void sink_it_(const spdlog::details::log_msg& msg) override {
        // 转换日志级别
        QString level = levelToString(msg.level);

        // 提取日志器名称作为来源
        QString source = QString::fromStdString(
            std::string(msg.logger_name.data(), msg.logger_name.size()));

        // 提取消息内容
        QString message = QString::fromStdString(
            std::string(msg.payload.data(), msg.payload.size()));

        // 转换时间戳
        auto time_point = msg.time;
        auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
            time_point.time_since_epoch()).count();
        QDateTime timestamp = QDateTime::fromMSecsSinceEpoch(ms);

        // 通过发射器广播日志
        LogBroadcastEmitter::instance()->emitLogEntry(timestamp, level, source, message);
    }

    /**
     * @brief 刷新日志
     */
    void flush_() override {
        // 无需特殊处理
    }

private:
    /**
     * @brief 转换 spdlog 日志级别为字符串
     */
    QString levelToString(spdlog::level::level_enum level) const {
        switch (level) {
            case spdlog::level::trace:
                return "debug";
            case spdlog::level::debug:
                return "debug";
            case spdlog::level::info:
                return "info";
            case spdlog::level::warn:
                return "warn";
            case spdlog::level::err:
                return "error";
            case spdlog::level::critical:
                return "error";
            default:
                return "info";
        }
    }
};

// 多线程安全版本的 LogBroadcastSink
using LogBroadcastSinkMt = LogBroadcastSink<std::mutex>;

/**
 * @brief 安装日志广播 Sink 到全局日志器
 * @details 调用此函数后，所有通过 spdlog 记录的日志都会广播到 UI
 */
void installLogBroadcastSink();

/**
 * @brief 安装日志广播 Sink 到指定日志器
 * @param loggerName 日志器名称
 */
void installLogBroadcastSink(const QString& loggerName);

} // namespace infrastructure::logging
